/******************************************************************************
 * @file     filesystem.c
 * @version  V0.10
 * $Revision: 1 $
 * $Date: 13/07/10 1:17p $ 
 * @brief    NUC970 series filesystem source file
 *
 * @note
 * Copyright (C) 2013 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/ 
#include "filesystem.h"
#include "wbio.h"
#include "wblib.h"
#include "sdglue.h"
#include "usbd.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SectorSize 512
#define WriteLen  512
static UINT8 bpb_sample[]=
{
	0xEB, 0x58, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x08, 0x22, 0x00,
	0x02, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x3F, 0x00, 0xFF, 0x00, 0x3F, 0x00, 0x00, 0x00,
	0xC1, 0x0F, 0x2F, 0x00, 0xBF, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
	0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x80, 0x00, 0x29, 0x2F, 0x39, 0x6C, 0x80, 0x4E, 0x4F, 0x20, 0x4E, 0x41, 0x4D, 0x45, 0x20, 0x20,
	0x20, 0x20, 0x46, 0x41, 0x54, 0x33, 0x32, 0x20, 0x20, 0x20, 0x33, 0xC9, 0x8E, 0xD1, 0xBC, 0xF4,
	0x7B, 0x8E, 0xC1, 0x8E, 0xD9, 0xBD, 0x00, 0x7C, 0x88, 0x4E, 0x02, 0x8A, 0x56, 0x40, 0xB4, 0x08,
	0xCD, 0x13, 0x73, 0x05, 0xB9, 0xFF, 0xFF, 0x8A, 0xF1, 0x66, 0x0F, 0xB6, 0xC6, 0x40, 0x66, 0x0F,
	0xB6, 0xD1, 0x80, 0xE2, 0x3F, 0xF7, 0xE2, 0x86, 0xCD, 0xC0, 0xED, 0x06, 0x41, 0x66, 0x0F, 0xB7,
	0xC9, 0x66, 0xF7, 0xE1, 0x66, 0x89, 0x46, 0xF8, 0x83, 0x7E, 0x16, 0x00, 0x75, 0x38, 0x83, 0x7E,
	0x2A, 0x00, 0x77, 0x32, 0x66, 0x8B, 0x46, 0x1C, 0x66, 0x83, 0xC0, 0x0C, 0xBB, 0x00, 0x80, 0xB9,
	0x01, 0x00, 0xE8, 0x2B, 0x00, 0xE9, 0x48, 0x03, 0xA0, 0xFA, 0x7D, 0xB4, 0x7D, 0x8B, 0xF0, 0xAC,
	0x84, 0xC0, 0x74, 0x17, 0x3C, 0xFF, 0x74, 0x09, 0xB4, 0x0E, 0xBB, 0x07, 0x00, 0xCD, 0x10, 0xEB,
	0xEE, 0xA0, 0xFB, 0x7D, 0xEB, 0xE5, 0xA0, 0xF9, 0x7D, 0xEB, 0xE0, 0x98, 0xCD, 0x16, 0xCD, 0x19,
	0x66, 0x60, 0x66, 0x3B, 0x46, 0xF8, 0x0F, 0x82, 0x4A, 0x00, 0x66, 0x6A, 0x00, 0x66, 0x50, 0x06,
	0x53, 0x66, 0x68, 0x10, 0x00, 0x01, 0x00, 0x80, 0x7E, 0x02, 0x00, 0x0F, 0x85, 0x20, 0x00, 0xB4,
	0x41, 0xBB, 0xAA, 0x55, 0x8A, 0x56, 0x40, 0xCD, 0x13, 0x0F, 0x82, 0x1C, 0x00, 0x81, 0xFB, 0x55,
	0xAA, 0x0F, 0x85, 0x14, 0x00, 0xF6, 0xC1, 0x01, 0x0F, 0x84, 0x0D, 0x00, 0xFE, 0x46, 0x02, 0xB4,
	0x42, 0x8A, 0x56, 0x40, 0x8B, 0xF4, 0xCD, 0x13, 0xB0, 0xF9, 0x66, 0x58, 0x66, 0x58, 0x66, 0x58,
	0x66, 0x58, 0xEB, 0x2A, 0x66, 0x33, 0xD2, 0x66, 0x0F, 0xB7, 0x4E, 0x18, 0x66, 0xF7, 0xF1, 0xFE,
	0xC2, 0x8A, 0xCA, 0x66, 0x8B, 0xD0, 0x66, 0xC1, 0xEA, 0x10, 0xF7, 0x76, 0x1A, 0x86, 0xD6, 0x8A,
	0x56, 0x40, 0x8A, 0xE8, 0xC0, 0xE4, 0x06, 0x0A, 0xCC, 0xB8, 0x01, 0x02, 0xCD, 0x13, 0x66, 0x61,
	0x0F, 0x82, 0x54, 0xFF, 0x81, 0xC3, 0x00, 0x02, 0x66, 0x40, 0x49, 0x0F, 0x85, 0x71, 0xFF, 0xC3,
	0x4E, 0x54, 0x4C, 0x44, 0x52, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x0A, 0x52, 0x65,
	0x6D, 0x6F, 0x76, 0x65, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x73, 0x20, 0x6F, 0x72, 0x20, 0x6F, 0x74,
	0x68, 0x65, 0x72, 0x20, 0x6D, 0x65, 0x64, 0x69, 0x61, 0x2E, 0xFF, 0x0D, 0x0A, 0x44, 0x69, 0x73,
	0x6B, 0x20, 0x65, 0x72, 0x72, 0x6F, 0x72, 0xFF, 0x0D, 0x0A, 0x50, 0x72, 0x65, 0x73, 0x73, 0x20,
	0x61, 0x6E, 0x79, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x72, 0x65, 0x73, 0x74, 0x61,
	0x72, 0x74, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAC, 0xCB, 0xD8, 0x00, 0x00, 0x55, 0xAA
};
//__align(32) UINT8 g_MemBuff[256*1024]; 
#define get_timer_ticks()		sysGetTicks(TIMER0)

INT fmiSDWrite(UINT32 uStartSecN,UINT32 nCount,UINT8 *pucSecBuff)
{
	fmiSD_Write(uStartSecN, nCount, (UINT32)pucSecBuff);
return 1;
}
void fsFreeSector(UINT8 *buff){;}

/*
	TotalSize(sectors) : total sector size in the Device 
	HideSize(sectors)  : Reserve sector in the Device
*/
PMBR create_mbr(UINT32 TotalSize,UINT32 HideSize)
{
  PMBR mbr=NULL;
  mbr=(PMBR)malloc(sizeof(MBR));
	if(mbr==NULL) return NULL;
  memset(mbr, 0, sizeof(MBR));
  
  // pteStartSector(6 bit)= 1 & pteStartCylinder(10 bit)=0
  mbr->mbrPartition[0].pteStartSector  =0x01;
  mbr->mbrPartition[0].pteStartCylinder=0x00;
  mbr->mbrPartition[0].pteSystemID     =0x0B; //FAT32
  mbr->mbrPartition[0].pteEndHead      =0xFE; //value=254

  // pteEndSector(6 bit)=63 & pteEndCylinder(10 bit)=1023
  mbr->mbrPartition[0].pteEndSector    =0xFF;
  mbr->mbrPartition[0].pteEndCylinder  =0xFF;
  mbr->mbrPartition[0].pteFirstSector  =HideSize;
  mbr->mbrPartition[0].ptePartitionSize=TotalSize-(HideSize);
  mbr->mbrSignature=0xAA55;	
	fmiSDWrite(0, 1, (UINT8 *)mbr);
	SendAck(10);
	MSG_DEBUG("10\n");
  return mbr;  
}

INT32 FormatFat32(PMBR pmbr,UINT32 nCount)
{
	UINT8	*pucSecBuff=NULL, *pucPtr;
	INT		nSecPerClus;
	UINT32	uFatSize, uRsvSecNum=34, uRootClus=2;
	UINT32	uData1, uData2;
	UINT32	uLogSecNo;
	INT		nWrtSecNum, nStatus;	
	UINT8	FAT32Rsv[12] = { 0xF8, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x0F };
	UINT8	pucCode[] = { 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F,0xFF, 0xFF, 0xFF, 0x0F, 0xF8, 0xFF, 0xFF, 0x0F };
		/* 
	 * Clear Reserved sectors 
	 */	
	//pucSecBuff=(UINT8 *)malloc(sizeof(UINT8)* 512*WriteLen);   
  pucSecBuff = (UINT8 *)((UINT32) DOWNLOAD_BASE | NON_CACHE);
 
  if(pucSecBuff==NULL) return NULL;
	memset(pucSecBuff, 0x0, 512*WriteLen);
  pucPtr=pucSecBuff;
  SendAck(20);
  MSG_DEBUG("20\n"); 
	for (uLogSecNo = pmbr->mbrPartition[nCount].pteFirstSector, uData1 = 0; uData1 < uRsvSecNum; )
	{
		nWrtSecNum = MIN(WriteLen, (uRsvSecNum-uData1));
		nStatus = fmiSDWrite(uLogSecNo, nWrtSecNum, pucSecBuff);
		if (nStatus < 0)
		{
			fsFreeSector(pucSecBuff);
			return nStatus;
		}
		uLogSecNo += nWrtSecNum;
		uData1 += nWrtSecNum;
	}
	SendAck(25);
	MSG_DEBUG("25\n");
	/*
	 * Create the BPB sector
	 */
	memcpy(pucSecBuff, bpb_sample, sizeof(bpb_sample));
	pucPtr = pucSecBuff;
	
	/* determine the cluster size */
	if (pmbr->mbrPartition[nCount].ptePartitionSize < 16777216)			
		nSecPerClus = 8;						/* < 8G */
	else if (pmbr->mbrPartition[nCount].ptePartitionSize < 33554432)	
		nSecPerClus = 16;					/* 8G~16G */
	else if (pmbr->mbrPartition[nCount].ptePartitionSize < 67108864)	
		nSecPerClus = 32;					/* 16GB~32GB */
	else 
		nSecPerClus = 64;					/* >= 32GB */
		
	pucSecBuff[13] = nSecPerClus;

	//pmbr->mbrPartition[nCount].pteFirstSector
	/* sector per track */		
	PUT16_L(pucPtr,24,pmbr->mbrPartition[nCount].pteEndSector);
	
	/* number of heads */
	PUT16_L(pucPtr,26,pmbr->mbrPartition[nCount].pteStartHead);
	
	/* number of hidden sectors preceding the partition */
	PUT32_L(pucPtr,28,pmbr->mbrPartition[nCount].pteStartSector);

	/* write FAT32 total sector number */	
	PUT32_L(pucPtr,32,pmbr->mbrPartition[nCount].ptePartitionSize);
	
	/* calculate and write FAT size */
	uData1 = pmbr->mbrPartition[nCount].ptePartitionSize - (uRsvSecNum + 1);
	uData1 = ((uData1 + nSecPerClus - 1) / nSecPerClus) - 1;  // rough number of clusters
	uFatSize = 1;

	for (uData2 = 0; uData2 < uData1; uData2 += 128)
	{
		uFatSize ++;		// FAT1 and FAT2
		if (((uFatSize * 2) % nSecPerClus) == 0)
			uData1--;
	}
	//_debug_msg("uFatSize=%d\n", uFatSize);
	PUT32_L(pucPtr,36,uFatSize);

	/* Volume serial number */
	PUT32_L(pucPtr,67, get_timer_ticks());

	/* root directory cluster number */
	PUT32_L(pucPtr,44,uRootClus);
	
	/* pucFSInfo sector */
	PUT16_L(pucPtr,48,1);
	
	/* BPB bakcup sector */
	PUT16_L(pucPtr,50,6);

	/* write bpb sector */
	
	nStatus = fmiSDWrite(pmbr->mbrPartition[nCount].pteFirstSector, 1, pucSecBuff);
	if (nStatus < 0)
	{
		fsFreeSector(pucSecBuff);
		return nStatus;
	}

	/* write backup bpb sector */
	nStatus = fmiSDWrite(pmbr->mbrPartition[nCount].pteFirstSector+6, 1, pucSecBuff);
	if (nStatus < 0)
	{
		fsFreeSector(pucSecBuff);
		return nStatus;
	}
	SendAck(30);
	MSG_DEBUG("30\n");
	/* 
	 * Create pucFSInfo sector 
	 */
	memset(pucSecBuff, 0x0, 512);
	pucSecBuff[510] = 0x55;
	pucSecBuff[511] = 0xAA;
	
	/* lead signature */
	PUT32_L(pucPtr,0,0x41615252);
	
	/* structure signature */
	PUT32_L(pucPtr,484,0x61417272);
	
	/* free cluster count */
	PUT32_L(pucPtr,488,0xFFFFFFFF);
	
	/* Next free cluster */
	PUT32_L(pucPtr,492,2);
	
	/* write FS_Info sector */
	nStatus = fmiSDWrite(pmbr->mbrPartition[nCount].pteFirstSector+1, 1, pucSecBuff);
	if (nStatus < 0)
	{
		fsFreeSector(pucSecBuff);
		return nStatus;
	}

	/* write backup FS_Info sector */
	nStatus = fmiSDWrite(pmbr->mbrPartition[nCount].pteFirstSector+7, 1, pucSecBuff);
	if (nStatus < 0)
	{
		fsFreeSector(pucSecBuff);
		return nStatus;
	}
	SendAck(40);
	MSG_DEBUG("40\n");
	/* 
	 * Clear FAT table. The start of FAT table is ptPartition->uStartSecN + uRsvSecNum 
	 */	
	memset(pucSecBuff, 0x0, 512);
	uLogSecNo = pmbr->mbrPartition[nCount].pteFirstSector + uRsvSecNum;
	memcpy(pucSecBuff, pucCode, sizeof(pucCode));
	fmiSDWrite(uLogSecNo, 1, pucSecBuff);
	uLogSecNo++;

	memset(pucSecBuff, 0x0, 512*WriteLen);
	for (uData1 = 0; uData1 < uFatSize*2; )
	{
		nWrtSecNum = MIN(WriteLen, (uFatSize*2 - uData1));
		//MSG_DEBUG("nWrtSecNum = %d\n", nWrtSecNum);
		nStatus = fmiSDWrite(uLogSecNo, nWrtSecNum, pucSecBuff);
		if (nStatus < 0)
		{
			fsFreeSector(pucSecBuff);
			return nStatus;
		}
		uLogSecNo += nWrtSecNum;
		uData1 += nWrtSecNum;
		//if((uData1*40/(uFatSize*2))%5==0)
		{
			SendAck(40+(uData1*40/(uFatSize*2)));		
			MSG_DEBUG("%d\n",40+(uData1*40/(uFatSize*2)));
		}
	}
	SendAck(80);
	MSG_DEBUG("80\n");
	/* 
	 * Clear Root directory cluster
	 */
	memset(pucSecBuff, 0x0, 512);
	uLogSecNo = pmbr->mbrPartition[nCount].pteFirstSector + uRsvSecNum + uFatSize * 2 + (uRootClus - 2) * nSecPerClus;
	for (uData1 = 0; uData1 < nSecPerClus; uData1++, uLogSecNo++)
		fmiSDWrite(uLogSecNo, 1, pucSecBuff);

	memcpy(pucSecBuff, FAT32Rsv, 12);
	fmiSDWrite(pmbr->mbrPartition[nCount].pteFirstSector + uRsvSecNum, 1, pucSecBuff);

	fsFreeSector(pucSecBuff);
	SendAck(90);	
	MSG_DEBUG("90\n");
	return TRUE;
}
